/* s2 - in case of a bug, crash graceful
   Copyright (C) 2018 Ariadne Devos

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#ifndef _sHT_BUGS_H
#define _sHT_BUGS_H

#include <stddef.h>
#include <sys/types.h>
#include <limits.h>

#include <sHT/compiler.h>

/** Bug catching

  This is for detecting bugs of the class that cause memory corruption,
  where trying to continue only amplifies it. It is also for bugs that
  cause a smoke test to fail, in which case the application isn't useful
  at all until the bug isn't fixed.

  The functions are: @var{sHT_halt}, @var{sHT_assert}, @var{sHT_require}
  and @var{sHT_todo}. The last one is intentionally left undocumented,
  for a obvious reason here documented: it should not be needed outside
  proof-of-concepts. */

/** Check that a precondition is true.

  This is only for catching bugs. In particular, it may speculatively
  be ignored. */
#define sHT_require(b) \
  do { \
    if (sHT_unlikely(!(b))) \
      sHT_halt(#b); \
  } while (0)

/** Check that an invariant is true.

  This is only for catching bugs. In particular, it may speculatively
  be ignored. */
#define sHT_assert(b) sHT_require(b)

/* Last entry has .code == 0, and is the default */
struct sHT_bug_option {
	const char *msg;
	int code;
};

__attribute__((cold)) __attribute__((nonnull (1)))
_Noreturn void
sHT_bug(const struct sHT_bug_option *options, int code);

#define sHT_todo(b) do { if ((b)) __builtin_trap(); } while (0)

#endif
